#ifndef __THREAD__
#define __THREAD__
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/times.h>
#include <limits.h>
#include <signal.h>

/* 
   readString reads a string from the standard input. 
   Safe to use in multi-threaded system.
   String must be up to 1000 characters long and ends when the user presses <Enter>.
   The string is allocated dynamically, and therefore must be deleted afterwards.
*/
char* readString();


class entry_point{
public:
  void*(*entry)(void*);
  void *arg;
  pthread_cond_t *cond;
  pthread_mutex_t *mutex;

  entry_point(void*(*_entry)(void*),void *_arg,pthread_cond_t *_cond,pthread_mutex_t *_mutex)
  {
    entry = _entry;
    arg = _arg;
    cond = _cond;
    mutex = _mutex;
      
  }
};


class Thread{ 
 private:

  int myID;//an ID for programming issues
  
  pthread_t tid; // holds id of the library thread

  int blocked; // is the thread blocked (by some lock of a Mutex)

  int zombie; // the thread is zombie

  pthread_cond_t *timer_cond; /* for sub-threads suspension, untill the r started. */

  pthread_cond_t *job_cond;

  pthread_mutex_t *timer_mutex;
  pthread_mutex_t *job_mutex;  /* these two r used to sync the cond operation */

public:  

  // arguments : entry - the function of the thread, arg - arguments to entry
  Thread(void *(*entry)( void * ), void *arg);

  //Destructor : kills the thread tid
  ~Thread();

  // suspends this thread (tid)
  void suspend();

  // runs this thread with time as a time quantum, returns remaining time
  int run(int time);

  int getID();

  //blocks/unblocks/checks. only a thread can block itself

  void block();

  void release();

  int isBlocked();

		// ends the thread, Must be called at the end of the thread.
  void  exit();

};

class Mutex{
  class List{ // data structure for blocked threads
  public:
    Thread* t;
    List* next;
    
    List(Thread* newT){
      t=newT;
      next=NULL;
    }
  };

 private:
  List *head,*tail; // list of blocked threads
  pthread_mutex_t m; // library mutex
  int size; // number of blocked threads

 public:
  Mutex(); 
  ~Mutex();

  // if no thread is locking, t will now lock, otherwise t will be blocked (atomic)
  int lock(Thread* t);

  // unlock the Mutex, if some thread is blocked, unblock one of the blocked threads (atomic)
  int unlock();
};


extern Thread* self();// returns a pointer to currently running Thread


#ifdef DEBUG
#define TRACE(fmt,...) printf("%s %d: "fmt, __FUNCTION__, __LINE__ ,##__VA_ARGS__)
#else
#define TRACE
#endif /* DEBUG */


#endif

